package Server;

import java.io.IOException;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Queue;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentLinkedQueue;

import DBUtil.CNN;
import DBUtil.DBHandler;
import DBUtil.UserInfo;
import Tools.InfoFormat;
import Tools.Log;
import WindowsModule.UserInfoTakeing;
import WindowsModule.ZiyuanxinxiFenzhuang;
import XML.XML;
import XML.XMLNode;

/**
 * Res多线程服务端
 * 
 * 离线消息储备未完成。
 * 
 * @author Administrator
 * 
 */
public class ServerManager extends Server implements ServerListener {
	private class GateUserInfo {
		UserInfo uinfo;
		long gcode, gucode;

		public GateUserInfo(UserInfo uinfo,long gcode, long gucode) {
			super();
			this.uinfo = uinfo;
			this.gcode = gcode;
			this.gucode = gucode;
		}

		public UserInfo getUinfo() {
			return uinfo;
		}

		public long getGcode() {
			return gcode;
		}

		public long getGucode() {
			return gucode;
		}

		@Override
		public String toString() {
			return "[GateUserInfo userid:"+uinfo.getId()+"  gcode:"+gcode+"  gucode:"+gucode+" ]";
		}
	}
	private static DBHandler dbh = new DBHandler();
	/**
	 * 启动/获取服务端
	 * 
	 * @return
	 * @throws IOException
	 */
	public static ServerManager getServer() {
		if (serv == null) {
			try {
				port = Integer.parseInt(CNN.getConfig().GetPathValue("Serv:port").toString());
				serv = new ServerManager(port);
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
		return serv;
	}
	private UserDBHandle udbh = new UserDBHandle();
	public static int port = 1356;
	private volatile static ServerManager serv;// 单例
	public static void main(String[] args) {
//		getServer();
		String value = Arrays.toString(new Object[] { "dd", "dee", 11, 44 });
		System.out.println(value);

		String[] arr = value.substring(1, value.length() - 1).split(", ");
		System.out.println(Arrays.toString(arr));
	}

	private volatile Thread broadThread;

	private Map<String, GateUserInfo> users = new ConcurrentHashMap<String, ServerManager.GateUserInfo>();

	private volatile Queue<Message> messages = new ConcurrentLinkedQueue<Message>(); // 广播消息池
	
	private int onetime;
	
	private ServerManager(int port) throws IOException {
		super(port);

		// ///////////////////初始化日志////////////////////////

		// ///////////////////初始化广播线程////////////////////
		onetime = Integer.parseInt(CNN.getConfig().GetPathValue("Serv:user_grade_onelv_time").toString());
		broadThread = new Thread() {
			@Override
			public void run() {
				log("Broadcast thread startting...");
				long count = 0;
				while (broadThread == Thread.currentThread()) {
					try {
						//保持网关在线
						if((count++)%10==0){
							Message msg = new Message("<Pulse />", Message.ALL);
							pushMessage(msg );
						}
						// 刷消息出列
						while (!messages.isEmpty()) {
							Message msg = messages.poll();
							if (msg.type == Message.COMMON) {
								// /////////////发送群消息/////////////////
								String[] group = DBHandler.getGroupUser(msg.GroupID);// 取群用户
								for (int j = 0; j < group.length; j++) {
									if (!sendMessage(group[j], msg.msg)) {
										DBHandler.putLeaveMsg(group[j], msg.msg);
									}
								}
							} else
								// //////////////发送内/外网广播//////////////////////
								for (Long tid : clientTidCache.keySet()) {
									ClientThread t = clientTidCache.get(tid);
									if (t.getLogincmd() == null)
										continue;
									boolean b = msg.type == Message.ALL ? true : t.isOuterNet() ? msg.type == Message.OUTERNET : msg.type == Message.LAN;
									if (b && t != null) {
//										String code = msg.msg.get("code");
//										if (code != null && Long.parseLong(code) == t.getId()) {
//											continue;
//										}
										t.sendMessage(msg.msg);
									}
								}
							// ///////////////////////////////////////////
						}
						
						// 记录用户累计在线
						for (String userid : users.keySet()) {
							GateUserInfo gui = users.get(userid);
							gui.getUinfo().onlineTime +=100;
							if((gui.getUinfo().onlineTime>=getMaxTime((gui.getUinfo().getGrade()+1),onetime)?gui.getUinfo().upGrade():false)||gui.getUinfo().onlineTime%1000==0){
								if(udbh.isUpdateGradeOnlineTime(userid, gui.getUinfo().getGrade(), gui.getUinfo().onlineTime)){
									XMLNode cmd = new XMLNode("userinfo");
									cmd.put("gucode", gui.gucode);
									cmd.put("grade", gui.getUinfo().getGrade());
									cmd.put("integer",gui.getUinfo().getInteger());
									cmd.put("online_time", gui.getUinfo().onlineTime);
									sendMessage(gui.gcode, cmd );
								}
							}
						}
						Thread.sleep(100);
					} catch (Exception e) {
						log("[BroadThread]Excption:" + e);
					}
				}
				log("Broadcast thread end...");
			}

		};
		log("Server bind port: " + port);
		StartBroadThread();

	}
	
	private long getMaxTime(int i, int onetime) {
		long time = 0;
		for (int j = 1; j <= i; j++) {
			time += j*onetime;
		}
		return time;
	}

	@Override
	public void accepClientEvent(ClientAcceptEvent cae) {
		super.accepClientEvent(cae);// 进入客户池
		log(cae + "  Gate-Online: " + clientTidCache.size());
	}

	@Override
	public void ClientCloseEvent(ClientExitEvent cce) {
		super.ClientCloseEvent(cce);// 离开客户池
		
		int count=0;
		long gcode = cce.getCt().getId();
		for (Entry<String, GateUserInfo> ele : users.entrySet()) {
			if(ele.getValue().gcode==gcode){
				users.remove(ele.getKey());
				count ++;
			}
		}
		log(cce + "  Gate-Outline: Gate-Users: " + count);
	}

	/**
	 * 日志函数
	 * 
	 * @param log
	 * 
	 */
	private void log(Object log) {
		Log.print(log);

	}

	/**
	 * 添加广播消息
	 * 
	 * @param msg
	 */
	public void pushMessage(Message msg) {
		// Log.print("[pushMessage]"+msg);
		messages.add(msg);
	}

	/***************************************************************************
	 * 【请求事件】客户端请求处理
	 **************************************************************************/
	@Override
	public void requestEvent(ClientRequestEvent se) {
		XML cmd = se.cmd;
		XML logincmd = se.getCt().getLogincmd(); // 取登陆验证有效指令

		if (logincmd == null) {
			// 处理网关登录请求
			validateGateCmdAct(se.getCt(), cmd);
			return;
		} else if (validateCmdAct(se.getCt(), cmd)) {// 处理未验证用户请求
			return;
		}
		// ///////////////已验证用户请求处理//////////////////

		String flag = cmd.FLAG;
		String userId = cmd.get("userid");
		cmd.put("gcode", se.getCt().getId());

		if (flag.equalsIgnoreCase("seach")) {
			// //////////////////////////////////////////////// --> 搜索文件请求
			Log.print("搜索文件请求：" + cmd);
			cmd.put("tgcode", cmd.get("gcode"));
			cmd.put("tgucode", cmd.get("gucode"));
			pushMessage(new Message(cmd, Message.ALL));

		} else if (flag.equalsIgnoreCase("sresult")) {
			// //////////////////////////////////////////////// --> 转发搜索结果
			long code = Long.parseLong(cmd.get("tgcode"));
			cmd.put("gucode", cmd.get("tgucode"));
			sendMessage(code, cmd); // 转发给搜索者

		} else if (flag.equalsIgnoreCase("get")) {
			// //////////////////////////////////////////////// --> 索取文件种子请求
			Log.print("查找资源种子：" + cmd);
			cmd.put("tgcode", cmd.get("gcode"));
			cmd.put("tgucode", cmd.get("gucode"));
			pushMessage(new Message(cmd, Message.ALL));// 通知全网用户

		} else if (flag.equalsIgnoreCase("pip")) {
			// //////////////////////////////////////////////// --> // 返回种子索取信息
			Log.print("返回文件种子：" + cmd);
			long code = Long.parseLong(cmd.take("tgcode"));
			String gucode = cmd.take("tgucode");

			cmd.put("tgcode", cmd.get("gcode"));
			cmd.put("tgucode", cmd.get("gucode"));
			cmd.put("gucode", gucode);

			sendMessage(code, cmd);

		} else if (flag.equalsIgnoreCase("dloadGet")) {
			Log.print("请求下载资源  >> " + cmd);
			long code = Long.parseLong(cmd.take("tgcode"));
			String gucode = cmd.take("tgucode");
			cmd.put("tgcode", cmd.get("gcode"));
			cmd.put("tgucode", cmd.get("gucode"));
			cmd.put("gucode", gucode);
			if (code == 0) {
				GateUserInfo gui = users.get(cmd.get("userid"));
				if (gui != null) {
					code = gui.gcode;
					cmd.put("gucode", gui.gucode);
				}
			}
			sendMessage(code, cmd);

		} else if (flag.equalsIgnoreCase("dloadData")) {
			Log.print("[Forward] Pip:" + userId + "    Data: " + cmd.getData().length());
			long code = Long.parseLong(cmd.take("tgcode"));
			cmd.put("gucode", cmd.take("tgucode"));
			sendMessage(code, cmd);
		} else if (flag.equalsIgnoreCase("msg")) {
			// //////////////////////////////////////////////// --> 发送用户消息发送请求
			String userid = cmd.get("userid");
			GateUserInfo gui = users.get(userid);
			if (gui != null) {
				cmd.put("gucode", gui.gucode);
				cmd.put("userid", cmd.take("s_userid"));
				sendMessage(gui.gcode, cmd);
			}
		} else if (flag.equalsIgnoreCase("GroupMsg")) {
			// //////////////////////////////////////////////// --> 发送群消息请求
			int id = Integer.parseInt(cmd.get("id"));
			if (dbh.groupIn(id, userId)) {
				cmd.put("userid", userId);
				Message msg = new Message(cmd, Message.COMMON);
				msg.GroupID = id;
				pushMessage(msg);
			}
		} else if (flag.equalsIgnoreCase("add")) {
			// //////////////////////////////////////////////// --> 好友添加请求
			String id = cmd.get("userid");
			cmd.put("userid", userId);
			sendMessage(id, cmd);

		} else if (flag.equalsIgnoreCase("zhuce")) {
			// //////////////////////////////////////////////// --> 注册
			String zhuceCmd = cmd.get("cmd");
			if (zhuceCmd.equals("shen")) { // 获取省份
				List<String> list = udbh.getProvinces();
				StringBuffer sb = new StringBuffer();
				for (int i = 0; i < list.size(); i++) {
					if (i > 0)
						sb.append(",");
					sb.append(list.get(i));
				}
				cmd.put("value", sb.toString());
				se.getCt().sendMessage(cmd);
			} else if (zhuceCmd.equals("submit")) { // 注册提交
				String value = cmd.get("value");
				String[] args = value.substring(1, value.length() - 1).split(",");
				for (int i = 0; i < args.length; i++) {
					args[i] = args[i].trim();
				}
				boolean suc = udbh.isInsert(args[0], args[1], args[2], args[3], Integer.parseInt(args[4]), Integer.parseInt(args[5]), Integer.parseInt(args[6]), args[7], args[8], args[9], args[10], args[11], args[12], Integer.parseInt(args[13]), args[14], args[15], args[16]);
				cmd.put("value", suc);
				se.getCt().sendMessage(cmd);
				Log.print("注册用户：" + Arrays.toString(args) + "  " + suc);
			}
		} else if (flag.equalsIgnoreCase("ResContribute")) {
			String userid = cmd.get("userid");
			if(DBHandler.resContribute(userid)){
				GateUserInfo ui = users.get(userid);
				if(ui!=null){
					ui.uinfo.setInteger(ui.uinfo.getInteger()+1);
				}
			}
		} else if (flag.equalsIgnoreCase("zhmm")) {
			String userid = cmd.get("userid");
			String tiwen = cmd.get("tiwen");
			String daan = cmd.get("daan");
			String pwd = cmd.get("pwd");

			boolean suc = udbh.zhaohuimima(userid, tiwen, daan, pwd);

			cmd.put("value", suc);
			se.getCt().sendMessage(cmd);
		} else if (flag.equalsIgnoreCase("update")) {
			if (cmd.get("cmd").equals("get")) {
				String userid = cmd.get("userid");
				// 安全设置
				StringBuffer oldpassword = new StringBuffer();
				StringBuffer tiwen = new StringBuffer();
				StringBuffer daan = new StringBuffer();
				// 个人资料
				StringBuffer sname = new StringBuffer();
				StringBuffer sex = new StringBuffer();
				java.sql.Date Birthday = new java.sql.Date(100000);
				StringBuffer aihao = new StringBuffer();
				StringBuffer blood = new StringBuffer();
				StringBuffer xizuo = new StringBuffer();
				StringBuffer province = new StringBuffer();
				StringBuffer city = new StringBuffer();
				StringBuffer Email = new StringBuffer();
				StringBuffer explain = new StringBuffer();

				boolean suc = udbh.selectUser(userid, oldpassword, tiwen, daan, sname, sex, Birthday, aihao, blood, xizuo, province, city, Email, explain);
				if (suc) {
					cmd.put("value", tiwen + "," + daan + "," + sname + "," + sex + "," + Birthday.getTime() + "," + aihao + "," + blood + "," + xizuo + "," + province + "," + city + "," + Email + "," + explain + ",");
				} else {
					cmd.take("value");
				}
				se.getCt().sendMessage(cmd);
			} else if (cmd.get("cmd").equals("pwd")) {
				String userid = cmd.get("userid");
				boolean suc = udbh.isUpdate(cmd.take("pwdnew"), cmd.take("tiwen"), cmd.take("daan"), userid, cmd.take("pwdold"));
				cmd.put("result", suc);
				se.getCt().sendMessage(cmd);
			} else if (cmd.get("cmd").equals("info")) {
				Log.print("修改资料：" + cmd);
				String userid = cmd.get("userid");
				boolean suc = udbh.isUpdateInfo(cmd.take("name"), cmd.take("sex"), new Date(Long.parseLong(cmd.take("birthday"))).getTime(), cmd.take("aihao"), cmd.take("blood"), cmd.take("xinzuo"), Integer.parseInt(cmd.take("province")), cmd.take("city"), cmd.take("email"), cmd.getData(true), userid);
				cmd.put("result", suc);
				se.getCt().sendMessage(cmd);
			}

		} else if (flag.equalsIgnoreCase("talkmsg")) {
			Log.print("TalkMsg " + cmd);

			String userid = cmd.get("userid");
			cmd.put("userid", userId);
			sendMessage(userid, cmd);

		} else if (flag.equalsIgnoreCase("talk")) {
			Log.print("Talk " + cmd);
			String userid = cmd.get("userid");
			UserInfoTakeing ust = udbh.selectUserInfo(userid);
			cmd.put("name", ust.getName());
			cmd.put("sex", ust.getSex());
			cmd.put("address", ust.getAddress());
			cmd.put("email", ust.getEmail());
			se.getCt().sendMessage(cmd);

			// 告诉对方弹出消息框
			ust = udbh.selectUserInfo(userId);
			cmd.put("userid", userId);
			cmd.put("open", "true");
			cmd.put("name", ust.getName());
			cmd.put("sex", ust.getSex());
			cmd.put("address", ust.getAddress());
			cmd.put("email", ust.getEmail());
			sendMessage(userid, cmd);

		} else if (flag.equalsIgnoreCase("resInfo")) {
			XMLNode xn = cmd;
			// 检测数据库
			String md5 = xn.get("md5");
			if (!DBUtil.DBHandler.resExists(md5)) {
				String type = InfoFormat.getTypeStr(xn.get("name"));
				String Title = xn.get("name");
				Long lon = Long.valueOf(0);
				try {
					lon = new Long(xn.get("size"));
				} catch (Exception e) {
				}
				Integer inte = new Integer(0);
				try {
					inte = new Integer(xn.get("Pip"));
				} catch (Exception e) {
				}
				DBUtil.DBHandler.AddRes(md5, type, Title, lon, inte);
			}
			// 读取数据库
			ZiyuanxinxiFenzhuang z = udbh.Ziyuanxinxi(md5);
			xn.put("title", z.getTitle());
			xn.put("length", z.getLength());
			xn.put("time", z.getTime());
			xn.put("type", z.getType());
			xn.put("pipSum", z.getPipsum());
			xn.put("resNum", z.getZiyuanshuliang());
			xn.put("resJiazi", z.getZiyuanjiazi());
			se.getCt().sendMessage(xn);
		} else if (flag.equalsIgnoreCase("pulse")) {
			se.getCt().lasttime = System.currentTimeMillis();
		} else if (flag.equalsIgnoreCase("Outline")) {
			users.remove(cmd.get("userid"));
			log("Outline  " + userId);
		} else {
			// ////////////////////////////////////////////////
			Log.print("[未知指令]" + se.getCt().getSocket().getInetAddress() + " cmd:" + cmd);

		}
	}

	public void SendInform(String userid, String msg) {
		SendInform(userid, new XML(msg), false);
	}

	public void SendInform(String userid, XML msg) {
		SendInform(userid, msg, false);
	}

	/**
	 * 向指定用户的好友发送指令
	 * 
	 * @param client
	 *            要向好友发送消息的客户
	 * @param msg
	 *            消息内容
	 * @param leave
	 *            不在线时，转为离线消息
	 */
	public void SendInform(String userid, XML msg, boolean leave) {
		if (userid == null || userid.equals("*"))
			return;
		String[] flId = DBHandler.getFellowID(userid);// 从数据库获得好友列表
		for (int i = 0; i < flId.length; i++) {
			if (!sendMessage(flId[i], msg)) {
				if (leave)
					DBHandler.putLeaveMsg(flId[i], msg);// --离线消息
			}
		}
	}

	@Override
	public boolean sendMessage(String userid, XMLNode xmlnode) {
		GateUserInfo gui = users.get(userid);
		if (gui != null) {
			xmlnode.put("gucode", gui.gucode);
			return super.sendMessage(gui.gcode, xmlnode);
		}
		return false;
	}

	private void StartBroadThread() {
		broadThread.start();// 启动广播线程
	}

	/**
	 * 处理未验证用户的请求，如：登陆请求
	 * 
	 */
	public boolean validateCmdAct(ClientThread ct, XML cmd) {
		String command = cmd.FLAG.toUpperCase();
		if (command.equalsIgnoreCase("login")) {
			long gcode = ct.getId();
			String gucode = cmd.get("gucode");
			String userid = cmd.get("userid");
			String pwd = cmd.get("password");

			if (userid != null && (userid.equals("*") || DBHandler.existUser(userid, pwd != null ? pwd : ""))) {
				// 检测是否已登录,强迫对方下线
				/*
				 * if (!id.equals("*")) { int i = s.getUsernameIndex(id); if (i
				 * != -1) { try { xmlFlag flg = new xmlFlag(null, "drop");
				 * flg.put("Address", client.getInetAddress() .toString());
				 * this.sendMessage(flg); this.client.close(); } catch
				 * (IOException e) { // TODO Auto-generated catch block
				 * e.printStackTrace(); } } }
				 */
				cmd.FLAG = "OK";
				cmd.clear();
				if (userid.equals("*")) {
					cmd.put("userid", userid);
					cmd.put("integral", 0);
					cmd.put("grade", 0);
					cmd.put("online_time", 0);
					ct.sendMessage(cmd);
				} else {
					// 顶替下线
					GateUserInfo gui = users.get(userid);
					if(gui!=null){
						Log.print("Login tick, userid=" + userid+"  "+gui); 
						XMLNode msg = new XMLNode("Outline");
						msg.put("userid", userid);
						sendMessage(gui.gcode, msg);
						for(;users.containsKey(userid);){
							try {
								Thread.sleep(1000);
							} catch (InterruptedException e) {
								e.printStackTrace();
							}
						}
					}
					// ---通知用户,登陆成功
					Log.print("Login cache, userid=" + userid); 
					UserInfo ui = dbh.getUser(userid);
					users.put(userid, new GateUserInfo(ui, gcode, Long.parseLong(gucode)));
					cmd.put("userid", userid);
					cmd.put("integral", ui.getInteger());
					cmd.put("grade", ui.getGrade());
					cmd.put("online_time", ui.onlineTime);
					ct.sendMessage(cmd);
				}
				Log.print("Login success, userid=" + userid); // 登录成功！
				// =============保存用户的基本信息=================

				// --更新用户数据库上线信息
				if (!userid.equals("*")) {
					DBHandler.setOlineIp(userid, cmd.get("address"));

					// --通知好友用户上线

					cmd.FLAG = "OnLine"; // 修改指令码
					cmd.take("password"); // 清除密码属性
					cmd.put("address", ct.getSocket().getInetAddress().toString());// 添加IP地址属性

					if (!ct.isOuterNet()) {
						cmd.put("sport", null); // 内网用户：清除文件服务端口号
					}
					SendInform(userid, cmd); // 向好友们发送上线通知
				}

			} else {
				Log.print("Login Lost, userid=" + userid + "\taddress:" + ct.getSocket().getInetAddress());
				cmd.FLAG = "NO";
				ct.sendMessage(cmd);
				try {
					Thread.sleep(1000);
				} catch (InterruptedException e) {
				}
				// ct.close();// 未知客户，关闭客户线程
			}
			return true;
		} else {

		}
		return false;
	}

	/**
	 * 处理未验证网关请求，如：登陆请求
	 * 
	 */
	public boolean validateGateCmdAct(ClientThread ct, XML cmd) {
		String command = cmd.FLAG.toUpperCase();
		if (command.equalsIgnoreCase("login")) {
			String userid = cmd.get("userid");
			String pwd = cmd.get("password");

			if (userid != null && (userid.equals("*") || DBHandler.existUser(userid, pwd != null ? pwd : ""))) {
				// 检测是否已登录,强迫对方下线
				/*
				 * if (!id.equals("*")) { int i = s.getUsernameIndex(id); if (i
				 * != -1) { try { xmlFlag flg = new xmlFlag(null, "drop");
				 * flg.put("Address", client.getInetAddress() .toString());
				 * this.sendMessage(flg); this.client.close(); } catch
				 * (IOException e) { // TODO Auto-generated catch block
				 * e.printStackTrace(); } } }
				 */
				if (userid.equals("*")) {
					userid = ct.getName().replace("Thread", "User");
					ct.sendMessage("<GOK userid=\"" + userid + "\" />");
				} else {
					// ---通知用户,登陆成功
					UserInfo ui = dbh.getUser(userid);
					ct.sendMessage("<GOK userid=\"" + userid + "\" />");
				}
				Log.print("Login success, userid=" + userid); // 登录成功！
				// =============保存用户的基本信息=================

				clientUidCache.remove(ct.getName());
				clientUidCache.put(userid, ct);
				ct.setName(userid);
				ct.setLogincmd(cmd.clone()); // 记录登录请求

				// --更新用户数据库上线信息
				if (!userid.equals("*")) {
					DBHandler.setOlineIp(userid, ct.getSocket().getInetAddress().toString().substring(1));
				}
			} else {
				Log.print("Login Fault, userid=" + userid + "\taddress:" + ct.getSocket().getInetAddress());
				ct.sendMessage("<GNO />");
				try {
					Thread.sleep(1000);
				} catch (InterruptedException e) {
				}
			}
			return true;
		}
		return false;
	}
}
